<?php
/**
 * Bair Config Class
 *
 * @package Bair
 * @subpackage Config
 */
class Bair_Config implements Bair_Config_Interface
{
	/**
	 * @var Bair
	 */
	protected $bair;
	
	protected $outdirectory = null;
	protected $outname = null;
	
	protected $type = Bair::JPG;
	protected $jpgQuality = 100;
	
	protected $maxWidth;
	protected $maxHeight;
	protected $scale;
	protected $keepAspectRatio = false;
	protected $forceResize = true;
	
	
	public function __construct($config = null)
	{
		if( $config !== null && is_array($config) )
			$this->_processConfig((array)$config);
	}
	
	/**
	 * @return Bair_Image_Info
	 */
	public function process($image)
	{
		$image = $this->getBair()->getEngine()->getImageInfo($image);
		
		$oldfilename = pathinfo($image->getFile());
		$oldfilename = $oldfilename['filename'];
		
		$newfilename = preg_replace('/(?<!%)%oldfile%/i', $oldfilename, $this->getOutName());
		
		$newfile = implode(DIRECTORY_SEPARATOR, array(rtrim($this->getOutDirectory(),'\\/'), $newfilename)) . '.' . $this->getOutType();
		
		//Default to same size
		$newImage = new Bair_Image_Info($image->getWidth(),$image->getHeight(),$this->getOutType(),$newfile);
		
		if( $this->getForceResize() )
		{
			$newImage = $this->_resize($newImage);
		}
		elseif( $image->getWidth() > $this->getMaxWidth() || $image->getHeight() > $this->getMaxHeight() )
		{
			$newImage = $this->_resize($newImage);
		}
		
		if( $this->getOutType() === Bair::JPG )
			$newImage->setOption('JPGQuality', $this->getJPGQuality());
		
		return $this->getBair()->getEngine()->resize($image->getFile(), $newImage);
	}
	
	protected function _resize(Bair_Image_Info $image)
	{
		if( $this->getScale() )
		{
			$scale = $this->getScale();
			
			if( $this->getMaxWidth() && $scale * $image->getWidth() > $this->getMaxWidth() )
			{
				$scale =  $this->getMaxWidth() / $image->getWidth();
			}
			
			if( $this->getMaxHeight() && $scale * $image->getHeight() > $this->getMaxHeight() )
			{
				$scale = $this->getMaxHeight() / $image->getHeight();
			}
			
			$image->setHeight($image->getHeight() * $scale)
			      ->setWidth($image->getWidth() * $scale);
		}
		elseif( $this->getKeepAspectRatio() )
		{
			if( $this->getMaxHeight() && !$this->getMaxWidth() )
			{
				$sizefactor = $this->getMaxHeight() / $image->getHeight();
				
				$image->setHeight($image->getHeight() * $sizefactor)
				      ->setWidth($image->getWidth() * $sizefactor);
			}
			elseif( !$this->getMaxHeight() && $this->getMaxWidth() )
			{
				$sizefactor = $this->getMaxWidth() / $image->getWidth();
				
				$image->setHeight($image->getHeight() * $sizefactor)
				      ->setWidth($image->getWidth() * $sizefactor);
			}
			elseif( $this->getMaxHeight() && $this->getMaxWidth() )
			{
				//Do twice to make sure the image is constrained to both dimensions
				for( $i = 0; $i < 2; $i++ )
				{
					$sizefactor = 1.0;
					
					if( $image->getWidth() > $this->getMaxWidth() )
					{
						$sizefactor = $this->getMaxWidth() / $image->getWidth();
					}
					elseif( $image->getHeight() > $this->getMaxHeight() )
					{
						$sizefactor = $this->getMaxHeight() / $image->getHeight();
					}
					
					$image->setHeight($image->getHeight() * $sizefactor)
					      ->setWidth($image->getWidth() * $sizefactor);
				}
			}
			else
			{
				throw new Bair_Exception("Max Width or Max Height have not been provided");
			}
		}
		else
		{
			if( $this->getMaxWidth() && $image->getWidth() > $this->getMaxWidth() )
			{
				$image->setWidth($this->getMaxWidth());
			}
			
			if( $this->getMaxWidth() && $image->getHeight() > $this->getMaxHeight() )
			{
				$image->setHeight($this->getMaxHeight());
			}
		}
		
		return $image;
	}
	
	/**
	 * @return Bair
	 */
	public function getBair()
	{
		return $this->bair;
	}
	
	public function getMaxWidth()
	{
		return $this->maxWidth;
	}
	
	public function getMaxHeight()
	{
		return $this->maxHeight;
	}
	
	public function getOutType()
	{
		return $this->type;
	}
	
	public function getOutName()
	{
		return $this->outname;
	}
	
	public function getOutDirectory()
	{
		return $this->outdirectory;
	}
	
	public function getScale()
	{
		return $this->scale;
	}
	
	public function getKeepAspectRatio()
	{
		return $this->keepAspectRatio;
	}
	
	public function getForceResize()
	{
		return $this->forceResize;
	}
	
	public function getJPGQuality()
	{
		return $this->jpgQuality;
	}
	
	public function setBair(Bair $bair)
	{
		$this->bair = $bair;
		return $this;
	}
	
	public function setMaxWidth($width)
	{
		$this->maxWidth = (int)$width;
		
		return $this;
	}
	
	public function setMaxHeight($height)
	{
		$this->maxHeight = (int)$height;
		
		return $this;
	}
	
	public function setScale($percentage)
	{
		$this->scale = (double)$percentage;
		
		return $this;
	}
	
	public function setKeepAspectRatio($bool = true)
	{
		$this->keepAspectRatio = (bool)$bool;
		
		return $this;
	}
	
	public function setForceResize($bool = true)
	{
		$this->forceResize = (bool)$bool;
		
		return $this;
	}
	
	public function setOutDirectory($directory)
	{
		if( !is_writeable($directory) )
			throw new Bair_Exception("Directory '$directory' is not writeable");
		
		$this->outdirectory = $directory;
		return $this;
	}
	
	public function setOutName($name)
	{
		$this->outname = $name;
		
		return $this;
	}
	
	public function setOutType($type)
	{
		if( !in_array($type, array(Bair::JPG, Bair::GIF, Bair::PNG)) )
		{
			throw new Bair_Exception("Invalid Type '$type'");
		}
		
		$this->type = $type;
		
		return $this;
	}
	
	public function setJPGQuality($quality)
	{
		$quality = (int)$quality;
		
		if( $quality < 0 )
			$quality = 0;
		elseif( $quality > 100 )
			$quality = 100;
		
		$this->jpgQuality = $quality;
		
		return $this;
	}
	
	protected function _processConfig(array $config)
	{
		foreach( $config as $setting => $values )
		{
			$method = 'set' . $setting;
			
			if( method_exists($this, $method) )
			{
				$reflMethod = new ReflectionMethod(__CLASS__, $method);
				$reflMethod->invokeArgs($this, (array)$values);
			}
		}
	}
}